"""
此模块包含均线金叉死叉算法验证相关的技术指标计算函数
"""
import numpy as np
import pandas as pd
from datetime import datetime
from dateutil.relativedelta import relativedelta

# 这些是从MyTT库中提取的常用技术指标函数
def REF(Series, N=1):
    """
    向前引用N周期的数据
    """
    return pd.Series(Series).shift(N)

def EMA(Series, N=10):
    """
    指数移动平均线
    """
    return pd.Series(Series).ewm(span=N, adjust=False).mean()

def SUM(Series, N=20):
    """
    求和
    """
    return pd.Series(Series).rolling(N).sum()

def MA(Series, N=5):
    """
    简单移动平均线
    """
    return pd.Series(Series).rolling(N).mean()

def STD(Series, N=20):
    """
    标准差
    """
    return pd.Series(Series).rolling(N).std()

def MACD(Series, FAST=12, SLOW=26, M=9):
    """
    MACD指标
    """
    EMAFAST = EMA(Series, FAST)
    EMASLOW = EMA(Series, SLOW)
    DIFF = EMAFAST - EMASLOW
    DEA = EMA(DIFF, M)
    MACD = (DIFF - DEA) * 2
    return DIFF, DEA, MACD

# 新增博易大师技术指标算法
def calculate_boeyi_indicators(klines):
    """
    计算博易大师技术指标，包含Q值、操盘线和空头线
    """
    close = klines.close
    open_price = klines.open
    high = klines.high
    low = klines.low
    
    # 计算Q值
    Q = (3*close + low + open_price + high) / 6
    Q = pd.Series(Q)
    
    # 手动实现 REF 函数
    def ref(series, n=1):
        return series.shift(n)
    
    # 计算操盘线（26期Q值加权平均）
    terms = [
        26 * Q,
        25 * ref(Q, 1),
        24 * ref(Q, 2),
        23 * ref(Q, 3),
        22 * ref(Q, 4),
        21 * ref(Q, 5),
        20 * ref(Q, 6),
        19 * ref(Q, 7),
        18 * ref(Q, 8),
        17 * ref(Q, 9),
        16 * ref(Q, 10),
        15 * ref(Q, 11),
        14 * ref(Q, 12),
        13 * ref(Q, 13),
        12 * ref(Q, 14),
        11 * ref(Q, 15),
        10 * ref(Q, 16),
        9 * ref(Q, 17),
        8 * ref(Q, 18),
        7 * ref(Q, 19),
        6 * ref(Q, 20),
        5 * ref(Q, 21),
        4 * ref(Q, 22),
        3 * ref(Q, 23),
        2 * ref(Q, 24),
        ref(Q, 25)
    ]
    trading_line = sum(terms) / 351
    
    # 手动实现 EMA 函数
    def ema(series, n=10):
        return series.ewm(span=n, adjust=False).mean()
    
    # 计算空头线（操盘线的7期EMA）
    short_line = ema(trading_line, 7)
    
    # 计算买卖信号
    signals = pd.Series(np.nan, index=close.index)
    for i in range(2, len(close)):
        if trading_line.iloc[i-1] < short_line.iloc[i-1] and trading_line.iloc[i] > short_line.iloc[i]:
            signals.iloc[i] = 1  # 买入信号
        elif trading_line.iloc[i-1] > short_line.iloc[i-1] and trading_line.iloc[i] < short_line.iloc[i]:
            signals.iloc[i] = -1  # 卖出信号

    return trading_line, short_line, signals

# 修改计算交易信号函数，整合博易大师算法
def calculate_trading_signals(klines):
    """
    计算交易信号，整合博易大师技术指标算法
    """
    trading_line, short_line, signals = calculate_boeyi_indicators(klines)
    
    open_price = klines.open
    high = klines.high
    low = klines.low
    
    # 创建结果DataFrame
    result = pd.DataFrame({
        'datetime': klines.datetime,
        'open': open_price,
        'high': high,
        'low': low,
        'close': klines.close,
        'trading_line': trading_line,
        'short_line': short_line,
        'signal': signals.map({
            1: '上穿',
            -1: '下穿',
        }).fillna(np.nan)
    })
    
    # 处理日期格式
    result['date'] = result['datetime']
    result['date_str'] = [d.strftime('%Y-%m-%d') if hasattr(d, 'strftime') else str(d) for d in result['date']]
    
    return result

# 安全的日期格式化函数
def safe_date_format(dt_value):
    """
    安全地格式化日期时间值，处理各种可能的格式
    增强版：处理 akshare 返回的 datetime.date 对象和其他可能的日期格式
    """
    if pd.isna(dt_value):
        return "N/A"
    
    try:
        # 如果是 datetime.date、pandas Timestamp 或 datetime 对象
        if hasattr(dt_value, 'strftime'):
            return dt_value.strftime('%Y-%m-%d')  # 只显示日期部分，不显示时间
        
        # 如果是字符串，尝试解析
        if isinstance(dt_value, str):
            try:
                return pd.to_datetime(dt_value).strftime('%Y-%m-%d')
            except Exception:
                pass
        
        # 如果是时间戳（整数或浮点数）
        if isinstance(dt_value, (int, float)):
            try:
                return datetime.fromtimestamp(dt_value).strftime('%Y-%m-%d')
            except Exception:
                pass
    except Exception:
        pass
        
    # 如果所有尝试都失败，返回原始值的字符串表示
    return str(dt_value)